package luj.tool.jnproxyan.proxy.network.socks.actor.root;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import io.netty.channel.nio.NioEventLoopGroup;
import luj.data.api.Data;
import luj.data.api.DataContext;
import luj.data.api.type.TypePool;
import luj.net.api.NetContext;
import luj.tool.jnproxyan.proxy.database.DatabaseState;
import luj.tool.jnproxyan.proxy.util.data.DataDirtySaver;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.Record;
import org.jooq.Record1;
import org.jooq.SQLDialect;
import org.jooq.Select;
import org.jooq.Table;
import org.jooq.impl.DSL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.sqlite.SQLiteDataSource;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.atomic.AtomicLong;

import static com.google.common.base.Preconditions.checkState;

@Component
public class Socks5ActorFactory {

  public Socks5Actor create() throws Exception {
    TypePool types = _lujdata.createTypePool();
    DSLContext jooq = initDb();
    Long nextId = getNextId(jooq);

    DatabaseState dbState = new DatabaseState();
    dbState.setJooq(jooq);
    dbState.setDataTypes(types);
    dbState.setNextId(new AtomicLong(nextId));

    Data rule = null;//DataGlobalLoader.get(ConnectRules.class, dbState, _lujdata).loadOrCreate();
    return new Socks5Actor(rule, new NioEventLoopGroup(), _lujnet.createConnectionFactory(), initSsh(), dbState);
  }

  private DSLContext initDb() throws SQLException {
    Path dbPath = Paths.get("./dat/data.db").toAbsolutePath().normalize();
    checkState(Files.isRegularFile(dbPath), dbPath);

    SQLiteDataSource source = new SQLiteDataSource();
    source.setUrl("jdbc:sqlite:" + dbPath);

    Connection conn = source.getConnection();
    DSLContext jooq = DSL.using(conn, SQLDialect.SQLITE);

    try (var r = jooq.select(DSL.field("sqlite_version()"))) {
      LOG.debug("sqlite版本：{}", r.fetchOne(0));
    }
    return jooq;
  }

  private Long getNextId(DSLContext jooq) {
    try (Select<Record1<Long>> query = jooq.select(DSL.max(F_ID)).from(T_DATA)) {
      return query.fetchOptional()
          .map(Record1::value1)
          .map(v -> v + 1)
          .orElse(1L);
    }
  }

  private Session initSsh() throws JSchException {
    JSch jsch = new JSch();
    jsch.addIdentity("C:\\cygwin64\\home\\david\\.ssh\\id_rsa.classic");

    Session ssh = jsch.getSession("root", "47.57.69.155");
    ssh.setConfig("StrictHostKeyChecking", "no");

    return ssh;
  }

  private static final Logger LOG = LoggerFactory.getLogger(Socks5ActorFactory.class);

  private static final Table<Record> T_DATA = DataDirtySaver.T_DATA;
  private static final Field<Long> F_ID = DataDirtySaver.F_ID;

  @Autowired
  DataContext _lujdata;

  @Autowired
  NetContext _lujnet;
}
